#ifndef	DOBJ_H
#define	DOBJ_H

#include <stdint.h>

typedef	uint32_t	dobj_ptr_t;

#define	DOBJ_MAX_CHAR	(0xff)
#define	DOBJ_TRUE	(DOBJ_MAX_CHAR + 1)
#define	DOBJ_FALSE	(DOBJ_MAX_CHAR + 2)
#define	DOBJ_NULL	(DOBJ_MAX_CHAR + 3)
#define	DOBJ_CHAR(d)	(((d) & 0xffffff00) == 0)
#define	DOBJ_BOOL(d)	(((d) & 0xfffffffe) == 0x100)
#define	DOBJ_PORT(d)	(((d) & 0xf0ffff03) == 0x103)
#define	DOBJ_FINT(d)	(((d) & 0xf0000fff) == 0x300)
#define	DOBJ_INTERNAL(d)	(((d) & 0xf0000fff) == 0x301)

#define	DOBJ_PORT_IDX(d)	((((d) >> 2) & 0x3f) | ((d) >> 18))
#define	DOBJ_PORT_ENCODE(n)	\
	((((n) & 0x3f) << 2) | ((((n) >> 6) & 0xf) << 24) | 0x103)
#define	DOBJ_INT_ENCODE(n)	(((n) << 12) | 0x300)
#define	DOBJ_INTERNAL_ENCODE(x)	(((x) << 12) | 0x301)
#define	DOBJ_INT_VALUE(n)	((intptr_t)(int16_t)((n) >> 12))
#define	DOBJ_INTERNAL_DECODE(x)	((intptr_t)(int16_t)((x) >> 12))

#define	DOBJT_SIMPLE	(0x0)
#define	DOBJT_PAIR	(0x1)
#define	DOBJT_VECTOR	(0x2)
#define	DOBJT_PROC	(0x3)
#define	DOBJT_STRING	(0x4)
#define	DOBJT_CONT	(0x5)
#define	DOBJT_STK	(0x6)
#define	DOBJT_SYMBOL	(0x7)
#define	DOBJT_INT	(0x8)
#define	DOBJT_DOUBLE	(0x9)
#define	DOBJT_PAPROC	(0xa)

#define	DOBJ_TYPE(d)	((d) >> 28)
#define	DOBJ_PTR(d)	((d) & 0xfffffff)
#define	DOBJ_COMPOSE(t, i)	(((t) << 28) | ((i) & 0xfffffff))

struct	dobj_pair {
	dobj_ptr_t	dobj_car;
	dobj_ptr_t	dobj_cdr;
};

struct	dobj_vector {
	uint32_t	dobj_vec_length;
	dobj_ptr_t	dobj_vec_data[0];
};

struct	dobj_proc {
	uint32_t	dobj_proc_idx;
	dobj_ptr_t	dobj_upstk;
};

struct	dobj_string {
	uint32_t	dobj_str_length;
	uint8_t		dobj_str_data[4];	/* padding for fast parsing */
};

struct	dobj_cont {
	uint32_t	dobj_cont_ret;
	union {
		struct	{
			uint32_t	retip;
			dobj_ptr_t	retstk;
		} singleval;
		struct	{
			dobj_ptr_t	proc;
			dobj_ptr_t	cont;
		} multival;
	} dobj_cont_u;
#define	dobj_cont_retip		dobj_cont_u.singleval.retip
#define	dobj_cont_retstk	dobj_cont_u.singleval.retstk
#define	dobj_cont_bindproc	dobj_cont_u.multival.proc
#define	dobj_cont_retcont	dobj_cont_u.multival.cont
};

struct	dobj_stk {
	dobj_ptr_t	dobj_stk_cont;
	dobj_ptr_t	dobj_stk_proc;
	dobj_ptr_t	dobj_stk_data[0];
};

struct	dobj_symbol {
	uint32_t	dobj_sym_length;
	uint32_t	dobj_sym_hash;
	uint8_t		dobj_sym_data[0];
};

struct	dobj_paproc {
	uint32_t	dobj_pap_argn;
	dobj_ptr_t	dobj_pap_proc;
	dobj_ptr_t	dobj_pap_args[0];
};

struct	memenv;

dobj_ptr_t	alloc_list_dobj(struct memenv*, dobj_ptr_t*, int, int);
dobj_ptr_t	alloc_bigint_dobj(struct memenv*, intptr_t);
dobj_ptr_t	alloc_string_dobj(struct memenv*, const char*, int);
dobj_ptr_t	alloc_symbol_dobj(struct memenv*, const char*, int);
dobj_ptr_t	alloc_double_dobj(struct memenv*, double);
dobj_ptr_t	alloc_vector_dobj(struct memenv*, dobj_ptr_t*, int);

static	inline	dobj_ptr_t
alloc_int_dobj(struct memenv *env, intptr_t n)
{
	int16_t	sn = (int16_t)(uint16_t)(uintptr_t)n;

	if (sn == n) {
		return	(DOBJ_INT_ENCODE(n));
	}
	return	(alloc_bigint_dobj(env, n));
}

static	inline	dobj_ptr_t
alloc_bool_dobj(struct memenv *env, int t)
{
	return	((t == 0) ? DOBJ_FALSE : DOBJ_TRUE);
}

static	inline	dobj_ptr_t
alloc_char_dobj(struct memenv *env, uint8_t ch)
{
	return	((dobj_ptr_t)ch);
}

#endif	/* !DOBJ_H */

